package anim.adapter;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.util.ArrayList;

import javax.swing.text.Position;

import algoritmi.InformacijeOJednomKoraku;
import anim.Animator;
import anim.animacije.GrupaAnimacija;
import anim.animacije.Pauza;
import anim.animacije.PostaviInfo;
import anim.animacije.PostaviPozadinu;
import anim.animacije.PostaviTekst;
import anim.animacije.PremjestiCosV;
import anim.animacije.PremjestiLin;
import anim.animacije.PremjestiNLin;
import anim.objekti.ObojeniNatpis;
import anim.objekti.ObojeniRect;

/**
 * @author Aleksandar Stancic
 */

public class KoraciUAnimaciju {
	public static void konvertuj(Animator anim, ArrayList<InformacijeOJednomKoraku> koraci, int velicinaKesa, int velicinaMemorije)
	{
		final int boxW = 30, sirina = 500, visina = 300;
		final Dimension boxD = new Dimension(boxW, boxW);
		
		final Color bojaPozadineBloka = Color.LIGHT_GRAY;
		final Color bojaOkviraBloka = Color.blue;
		final Color bojaSlova = Color.black;
		
		final Color bojaPozadineReq = Color.CYAN;
	
		anim.resetujAnimator();
		
		boolean[] zauzet = new boolean[velicinaKesa];
		int[] okvir = new int[velicinaKesa];
		
		int kesOffX = (sirina - velicinaKesa * boxW) / 2;
		int kesOffY = visina - 120 - boxW;
		
		int memOffX = (sirina - velicinaMemorije * boxW) / 2;
		int memOffY = 50;
		
		int bPog = 0, bProm = 0;
		
		Point req0 = new Point(sirina / 2 - boxW / 2, visina + 10);
		Point req1 = new Point(sirina / 2 - boxW / 2, visina - boxW - 10);
		
		ObojeniNatpis[] pozMemorija = new ObojeniNatpis[velicinaMemorije];
		for(int i = 0; i < velicinaMemorije; ++i)
		{
			pozMemorija[i] = new ObojeniNatpis(new Point(memOffX + i * boxW, memOffY),
					boxD, bojaPozadineBloka, bojaOkviraBloka, bojaSlova, Integer.toString(i));
			anim.dodajObjekat(pozMemorija[i]);
		}
		
		ObojeniNatpis[] pozKes = new ObojeniNatpis[velicinaKesa];
		for(int i = 0; i < velicinaKesa; ++i)
		{
			pozKes[i] = new ObojeniNatpis(new Point(kesOffX + i * boxW, kesOffY),
					boxD, bojaPozadineBloka, bojaOkviraBloka, bojaSlova, " ");
			anim.dodajObjekat(pozKes[i]);
		}
		
		ObojeniNatpis[] fMemorija = new ObojeniNatpis[velicinaMemorije];
		for(int i = 0; i < velicinaMemorije; ++i)
		{
			fMemorija[i] = new ObojeniNatpis(new Point(memOffX + i * boxW, memOffY),
					boxD, bojaPozadineBloka, bojaOkviraBloka, bojaSlova, Integer.toString(i));
			anim.dodajObjekat(fMemorija[i]);
		}
		
		ObojeniNatpis req = new ObojeniNatpis(req0, boxD, bojaPozadineReq, bojaOkviraBloka, bojaSlova, Integer.toString(47));
		anim.dodajObjekat(req);
		
		int maxV = 0;
		for(InformacijeOJednomKoraku k : koraci)
			for(int n : k.getVrednosti())
				if(n > maxV) maxV = n;
		maxV++;
		
		Color[] gradient = new Color[maxV];
		float pola = maxV / 2.0f;
		
		for(int i = 0; i < maxV; ++i)
		{
			if(i < pola)
			{
				gradient[i] = new Color(1.0f, i / pola, 0.0f); 
			}
			else
			{
				gradient[i] = new Color(1.0f - (i - pola) / pola, 1.0f, 0.0f);
			}
		}
		
		for(InformacijeOJednomKoraku k : koraci)
		{	
			anim.dodajAnimaciju(new PostaviTekst(req, Integer.toString(k.staSeUbacuje())));
			anim.dodajAnimaciju(new PremjestiNLin(req, req1, 500));
			anim.dodajAnimaciju(new Pauza(100));
			
			if(!k.vecJeUKesu())
			{
				bProm++;
				anim.dodajAnimaciju(new PostaviInfo(anim, bPog, bProm));
				
				
				if(zauzet[k.naKojuPozicijuSeUbacuje()])
				{
					anim.dodajAnimaciju(new PostaviPozadinu(fMemorija[okvir[k.naKojuPozicijuSeUbacuje()]], bojaPozadineBloka));
					anim.dodajAnimaciju(new PremjestiCosV(fMemorija[okvir[k.naKojuPozicijuSeUbacuje()]],
							pozMemorija[okvir[k.naKojuPozicijuSeUbacuje()]].getPozicija(), 500));
				}
				
				anim.dodajAnimaciju(new PremjestiCosV(fMemorija[k.staSeUbacuje()],
						pozKes[k.naKojuPozicijuSeUbacuje()].getPozicija(), 800));
				
				zauzet[k.naKojuPozicijuSeUbacuje()] = true;
				okvir[k.naKojuPozicijuSeUbacuje()] = k.staSeUbacuje();
				
			}
			else
			{
				bPog++;
				anim.dodajAnimaciju(new PostaviInfo(anim, bPog, bProm));
			}
			
			anim.dodajAnimaciju(new Pauza(200));
			
			Point tp = new Point(kesOffX + k.naKojuPozicijuSeUbacuje() * boxW, kesOffY + boxW);
			anim.dodajAnimaciju(new PremjestiCosV(req, tp, 600 ));
			
			for(int i = 0; i < velicinaKesa; ++i)
				if(zauzet[i])
					anim.dodajAnimaciju(new PostaviPozadinu(fMemorija[okvir[i]], gradient[k.getVrednosti()[i]]));
			
			anim.dodajAnimaciju(new Pauza(200));
			
			anim.dodajAnimaciju(new PremjestiNLin(req, req0, 500));
			
		}
	}
	
	public static void generisiStackAnimaciju(Animator anim)
	{
		final int boxW = 30, sirina = 400, visina = 400;
		final Dimension boxD = new Dimension(boxW, boxW);
		
		final Color bojaPozadineBloka = Color.LIGHT_GRAY;
		final Color bojaOkviraBloka = Color.blue;
		final Color bojaSlova = Color.black;
		
		final Color bojaVrha = Color.red;
		final Color bojaDna = Color.green;
		
		final int brojElem = 30;
		final int maxS = 5;
		
		int sOffX = sirina - boxW * 4;
		int sOffY = visina / 2 - boxW / 2;
		int pos = 0;
		int n = 0;
		int[] stack = new int[brojElem];
		
		anim.resetujAnimator();
		
		ObojeniNatpis[] elem = new ObojeniNatpis[brojElem];
		for(int i = 0; i < brojElem; ++i)
		{
			elem[i] = new ObojeniNatpis(new Point(-boxW, sOffY),
					boxD, bojaPozadineBloka, bojaOkviraBloka, bojaSlova, Integer.toString(i));
			anim.dodajObjekat(elem[i]);
		}
		
		for(int i = 0; i < 3; ++i)
		{
			anim.dodajAnimaciju(new PremjestiNLin(elem[n], new Point(sOffX - pos * boxW, sOffY), 500));
			anim.dodajAnimaciju(new PostaviPozadinu(elem[n], bojaVrha));
			
			stack[pos] = n;
			pos++;
			n++;
			
			for(int x = 0; x < pos; ++x)
			{
				if(x == 0)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaDna));
				else if(x == pos - 1)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaVrha));
				else
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaPozadineBloka));
			}
		}
		
		for(int i = 0; i < brojElem - 3; ++i)
		{
			boolean push = Math.random() > 0.4;
			
			if(pos >= maxS) push = false;
			if(pos < 1) push = true;
			
			for(int x = 0; x < pos; ++x)
			{
				if(x == 0)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaDna));
				else if(x == pos - 1)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaVrha));
				else
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaPozadineBloka));
			}
			
			if(push)
			{
				anim.dodajAnimaciju(new PremjestiNLin(elem[n], new Point(sOffX - pos * boxW, sOffY), 500));
				
				stack[pos] = n;
				pos++;
				n++;
			}
			
			else
			{
				pos--;
				
				for(int x = 0; x < pos; ++x)
				{
					if(x == 0)
						anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaDna));
					else if(x == pos - 1)
						anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaVrha));
					else
						anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaPozadineBloka));
				}
				
				anim.dodajAnimaciju(new PremjestiNLin(elem[stack[pos]], new Point(-(boxW * 2), sOffY), 500));
				n++;
			}
			
			for(int x = 0; x < pos; ++x)
			{
				if(x == 0)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaDna));
				else if(x == pos - 1)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaVrha));
				else
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaPozadineBloka));
			}
			
		}
	}
	
	public static void generisiQueueAnimaciju(Animator anim)
	{
		final int boxW = 30, sirina = 400, visina = 400;
		final Dimension boxD = new Dimension(boxW, boxW);
		
		final Color bojaPozadineBloka = Color.LIGHT_GRAY;
		final Color bojaOkviraBloka = Color.blue;
		final Color bojaSlova = Color.black;
		
		final Color bojaVrha = Color.red;
		final Color bojaDna = Color.green;
		
		final int brojElem = 30;
		final int maxS = 5;
		
		int sOffX = sirina - boxW * 4;
		int sOffY = visina / 2 - boxW / 2;
		int pos = 0;
		int n = 0;
		int poz = 0;
		int[] stack = new int[brojElem];
		
		anim.resetujAnimator();
		
		ObojeniNatpis[] elem = new ObojeniNatpis[brojElem];
		for(int i = 0; i < brojElem; ++i)
		{
			elem[i] = new ObojeniNatpis(new Point(-boxW, sOffY),
					boxD, bojaPozadineBloka, bojaOkviraBloka, bojaSlova, Integer.toString(i));
			anim.dodajObjekat(elem[i]);
		}
		
		for(int i = 0; i < 3; ++i)
		{
			anim.dodajAnimaciju(new PremjestiNLin(elem[n], new Point(sOffX - pos * boxW, sOffY), 500));
			anim.dodajAnimaciju(new PostaviPozadinu(elem[n], bojaVrha));
			
			stack[pos] = n;
			pos++;
			n++;
			
			for(int x = poz; x < pos; ++x)
			{
				if(x == poz)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaDna));
				else if(x == pos - 1)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaVrha));
				else
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaPozadineBloka));
			}
		}
		
		for(int i = 0; i < brojElem - 3; ++i)
		{
			boolean enque = Math.random() > 0.4;
			
			if(pos - poz >= maxS) enque = false;
			if(pos - poz < 1) enque = true;
			
			for(int x = poz; x < pos; ++x)
			{
				if(x == poz)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaDna));
				else if(x == pos - 1)
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaVrha));
				else
					anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaPozadineBloka));
			}
			
			if(enque)
			{
				anim.dodajAnimaciju(new PremjestiNLin(elem[n], new Point(sOffX - pos * boxW, sOffY), 500));
				
				stack[pos] = n;
				pos++;
				n++;
			}
			
			else
			{
				GrupaAnimacija ga = new GrupaAnimacija();
				ga.dodajAnimaciju(new PremjestiNLin(elem[stack[poz]], new Point(sirina + boxW * 2, sOffY), 500));
				
				poz++;
				
				sOffX += boxW;
				
				for(int x = poz; x < pos; ++x)
				{
					if(x == poz)
						anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaDna));
					else if(x == pos - 1)
						anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaVrha));
					else
						anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaPozadineBloka));
					
					ga.dodajAnimaciju(new PremjestiLin(elem[stack[x]], new Point(sOffX - x * boxW, sOffY), 500));
				}
				anim.dodajAnimaciju(ga);
				
				
				n++;
			}
			
			
			
		}
		
		for(int x = poz; x < pos; ++x)
		{
			if(x == poz)
				anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaDna));
			else if(x == pos - 1)
				anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaVrha));
			else
				anim.dodajAnimaciju(new PostaviPozadinu(elem[stack[x]], bojaPozadineBloka));
		}
	}
	
}
